home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************\
- * *
- * *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** The Firmware. The Net. *
- * ***** ***** Portable. Compatible. *
- * ***** ***** Public Domain. *
- * ***** ***** By NORD><LINK. *
- * *
- * *
- * *
- * L2B.C - Level 2, Teil 2 *
- * *
- * angelegt: DC4OX *
- * modifiziert: *
- * Use of register keyword - April 1991 G8KBB *
- * Add second part of heard list support - check PID for L3/4 etc *
- * add link to IP router in 'tol3sw' to forward L2 encap frames *
- * add parameter to splcpy to control when it is OK to split *
- * remove spurious '== 1' and similar *
- * *
- * September 1993 - released as TheNet X-1J *
- * *
- * Added support for texnet in heard list in tol3sw() *
- * Correct digi bug ( didn't copy kiss digipeated frames ) *
- * *
- * Released as TheNet X-1J release 4, January 1995 *
- \**************************************************************************/
-
-
- /* Includes */
- /**************************************************************************/
-
- #include "all.h" /* allgemeine Festlegungen */
- #include "tntyp.h" /* Festlegungen/Datenstrukturen fuer den Level 2 */
- #include "l2s.h" /* Zugriff auf die State-Tabellen */
- #include "l2ext.h" /* globale Variable / nicht int-Funktionen */
-
-
- /**************************************************************************\
- * *
- * "check no activity" *
- * *
- * Alle aktiven Links (lnktbl, Linkstatus "Information Transfer") auf *
- * "keine Aktivitaet" abtesten. Ist der Keine-Aktivitaet-Timer aktiv (!= 0) *
- * und nach Dekrementieren abgelaufen, Disconnect einleiten. *
- * *
- * ACHTUNG: Diese Funktion muss sekuendlich aufgerufen werden, *
- * wird aber nur fuer TheNet benoetigt. *
- * *
- \**************************************************************************/
-
- #ifndef FIRMWARE
-
- VOID chknoa()
- {
- register unsigned n;
-
- for (n = LINKNMBR, lnkpoi = lnktbl; n != 0; --n, ++lnkpoi)
- if (lnkpoi->state >= L2SIXFER)
- if (lnkpoi->noatou != 0 && !(--lnkpoi->noatou)) disc();
- }
-
- #endif
-
-
-
-
-
- /**************************************************************************\
- * *
- * "new link" *
- * *
- * Link (lnkpoi) neu aufbauen. Wenn Link noch nicht aktiv war, die Anzahl *
- * aktiver Links (nmblks) erhoehen. *
- * *
- \**************************************************************************/
-
- VOID newlnk()
- {
- reslnk(); /* Sequenzvars/Timer ruecksetzen */
- setiT1(); /* FRACK-Timer neu starten */
- txfV2 = lnkpoi->V2link; /* welche Protokollversion */
- xsabm(); /* SABM senden */
- if (lnkpoi->state == L2SDSCED) /* neuer Link ? */
- ++nmblks; /* ja ... */
- lnkpoi->state = L2SLKSUP; /* Linkstatus "Link Setup" */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "disconnect link" *
- * *
- * Disconnect-Wunsch an aktuellen Link (lnkpoi) : *
- * *
- * Linkstatus "Disconnected" *
- * -> Ax.25-Parameter "frisch" *
- * *
- * Linkstatus "Link Setup" oder "Disconnect Request" *
- * -> Link aufloesen, neuer Linkstatus "Disconnected" *
- * *
- * sonst *
- * -> Empfangsinfoframeliste loeschen, Linkstatus bleibt, Flag "nach *
- * Loswerden aller zu sendenden Infoframes disconnecten" setzen *
- * *
- \**************************************************************************/
-
- VOID dsclnk()
- {
- register unsigned lstate;
-
- if (!(lstate = lnkpoi->state)) /* Disced, nur */
- inilbl(); /* AX-Pars neu */
- else
- if (lstate == L2SLKSUP || lstate == L2SDSCRQ) /* Linksetup oder */
- { /* Discreq, */
- clrlnk(); /* Link aufloesen */
- lnkpoi->state = L2SDSCED; /* Diconnected ! */
- }
- else
- { /* sonst */
- dealml(&lnkpoi->rcvdil); /* RX-Infoframe- */
- lnkpoi->rcvd = 0; /* loeschen und */
- lnkpoi->flag |= L2FDSLE; /* Flag, s.o. */
- }
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "information to link" *
- * *
- * Infobuffer, auf den imbp zeigt, an in diesem Buffer festgelegten Link *
- * (l2link) zwecks Aussendung als Paket weitergeben. Wenn nocgnc == YES *
- * keine "Erstickungskontrolle", sonst conctl beachten (s.u.). *
- * Der Infobuffer wird bei Weitergabe an den Link mit der normalen Level 2 *
- * PID versehen, der Keine-Aktivitaets-Timer wird neu gestartet. *
- * *
- * Return: TRUE - imbp wurde angenommen und an den Link weitergegeben *
- * FALSE - imbp wurde nicht angenommen wegen Congestion Control *
- * = Grenze der pro Link maximal zu speichernden Pakete *
- * (conctl) wuerde ueberschritten werden *
- * *
- \**************************************************************************/
-
- BOOLEAN itolnk(nocgnc,imbp)
- BOOLEAN nocgnc; /* "no congestion control" */
- register MBHEAD *imbp; /* "I message buffer pointer" */
-
- {
- register LNKBLK *linkp;
-
- if ((linkp = imbp->l2link)->tosend < conctl || nocgnc /* == YES */ )
- {
- imbp->l2fflg = L2CPID; /* Standard-L2-PID */
- relink(unlink(imbp),linkp->sendil.tail); /* -> ab in den Link */
- ++linkp->tosend; /* ein Sendepaket mehr */
- linkp->noatou = ininat; /* wieder Aktivitaet */
- return (TRUE); /* ... imbp angenommen */
- }
- return (FALSE); /* ... imbp abgelehnt */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "digipeat" *
- * *
- * Framebuffer, auf den fbp zeigt, abtesten, ob er ein zu digipeatendes *
- * Paket enthaelt. Wenn ja, Paket an den entsprechenden Port (falls ein *
- * bekannter Nachbarknoten direkt in der Digiliste folgt oder nach *
- * kompletten Digipeaten das Ziel ist, kann das Paket auch auf einem *
- * anderen als dem normalen HDLC-Port digipeatet werden) ausgeben. *
- * Das Paket muss schon durch takfhd() analysiert sein, die rxf...- *
- * Parameter muessen gesetzt sein. *
- * *
- * Return: YES - das Frame wurde entweder digipeatet, oder der *
- * Framebuffer wurde deallokiert, weil das Frame noch von *
- * einer anderen Station digipeatet werden muss oder ich *
- * nicht digipeaten darf *
- * NO - das Frame muss nicht mehr digipeated werden, hat alle *
- * noetigen Digipeater durchlaufen, ist zur Auswertung frei *
- * *
- \**************************************************************************/
-
- BOOLEAN digipt(fbpx)
- MBHEAD *fbpx;
-
- {
- register unsigned n; /* Zaehler */
- register char *viap; /* Zeiger in via-Liste */
- register MBHEAD *fbp = fbpx;
-
- viap = rxfhdr + L2ILEN; /* Anfang via-Liste */
- while (*viap != '\0') /* via-Liste durchgehen */
- {
- if (!(viap[L2IDLEN - 1] & L2CH)) /* zu digipeaten ? */
- {
- if (Rpar == YES && istome(viap) /*== TRUE*/)/* ja, darf ich */
- { /* und muss ich : */
- rwndmb(fbp); /* Zeiger auf Hbit */
- n = (unsigned)(viap - (rxfhdr+L2ILEN) + (L2ILEN+L2IDLEN));
- while (n-- != 0) getchr(fbp); /* berechnen */
- *(fbp->mbbp - 1) |= L2CH; /* Hbit setzen */
- viap += L2IDLEN; /* Nachbardigi */
- fbp->l2port = nbrprt( *viap != '\0' /* ich letzter ? */
- ? viap /* nein, Port Digi */
- : rxfhdr); /* ja, Port Ziel */
- fbp->l2fflg = 0; /* kein Linkframe */
- sdl2fr(fbp); /* Frame senden */
- }
- #ifdef KISSMODE
- else if( (crlmod == 2) && !ishost() && nmbfre > 64 )
- send_to_other_port( fbp );
- #endif
- else /* Frame ist noch nicht komplett digipeatet */
- dealmb(fbp); /* und/oder nix fuer mich, Frame wegwerfen */
- return (YES); /* fuer aufrufende Funk.: Frame ist weg ! */
- }
- viap += L2IDLEN; /* naechsten Digi in Digiliste untersuchen */
- }
- return (NO); /* fuer aufrufende Funk.: Frame auswerten ! */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "to level 3 switch" *
- * *
- * Aus I- oder UI-Frame (Framekopf fbp, Getzeiger/Zaehler auf 1. Byte *
- * hinter Level-2-Adressfeld) PID holen, falls vorhanden. Falls es nicht *
- * Level-2-PID ist, das Paket an die Level-3-Empfangsframeliste l3rxfl *
- * haengen. Im Framekopf wird in jedem Fall l2fflg auf PID, wenn vorhanden, *
- * oder 0 gesetzt, l2link auf den aktuellen Link (lnkpoi). *
- * *
- * Return: YES - das I/UI-Frame hat ein Nicht-Level-2-PID und wurde an die *
- * Level-3-Empfangsframeliste gehaengt *
- * NO - Frame hat Standard-Level-2-PID *
- * *
- * Mheard support - added conditionally on MONITORCMD *
- * if function running, and if the packet contains info, *
- * then have a look at the PID byte. Switch on it *
- * and update associated statistic. NOTE - IMPORTANT !! *
- * it is assumed that check_heard() has just run !!!!!! *
- \**************************************************************************/
-
- BOOLEAN tol3sw(fbp)
- register MBHEAD *fbp;
- {
- fbp->l2fflg = fbp->mbgc < fbp->mbpc ? getchr(fbp) : 0; /* PID holen */
- fbp->l2link = lnkpoi; /* Linkzeiger */
- if ((fbp->l2fflg & 0xFF) != L2CPID)
- { /* wenn nicht L2-Frame, Frame an */
- #ifdef MONITORCMD
-
- /* if heard list enabled ( mhlcount > 0 ), and the AX25 frame shows
- * that there is a valid PID in the frame, then examine it and set
- * the appropriate flag bits
- */
- if( mhlcount && (((rxfctl & 1)==0 ) || ( (rxfctl & 0xef ) == 3 )))
- switch( fbp->l2fflg & 0xff )
- {
- case PID_NETROM:
- mhptr->isnode = 1;
- break;
- #ifdef TEXNET
- case PID_TEXNET:
- mhptr->istexnet = 1;
- break;
- #endif
- case PID_IP:
- case PID_ARP:
- mhptr->istcpip = 1;
- }
- #endif
- #ifdef IPROUTE
-
- /* Now have another look and link it to the IP, ARP or L3
- * receive lists as approprriate. Only accept IP frames if
- * they are addressed to us !
- */
- switch( fbp->l2fflg & 0xff )
- {
- case PID_IP:
- if( cmpid( myid, rxfhdr ) )
- relink( fbp, iprxfl.tail );
- else
- return( NO );
- break;
- case PID_ARP:
- relink( fbp, arprxfl.tail );
- break;
- default:
- relink(fbp,l3rxfl.tail); /* Level 3 weiterreichen */
- }
- #else
- relink(fbp,l3rxfl.tail); /* Level 3 weiterreichen */
- #endif
- return (YES); /* Meldung, dass weitergereicht */
- }
- return (NO); /* Meldung, dass Level-2-Frame */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "level 2 information to level x" *
- * *
- * Infopakete aus dem aktuellen Link (lnkpoi) an hoehere Level weiter- *
- * reichen. nocgnc gibt an, ob der hoehere Level die "Erstickungskontrolle" *
- * (hier = Beruecksichtigung der maximal noch anzunehmenden I-Pakete) *
- * machen soll (NO) oder in jedem Fall alle uebermittelten I-Pakete *
- * annehmen muss (YES). Falls die I-Pakete vom hoeheren Level angenommen *
- * wurden, Empfangszaehler rcvd und Aktivitaetstimer noatou entsprechend *
- * updaten. Es wird l2link in den Framekoepfen der weitergereichten Pakete *
- * auf lnkpoi gesetzt und type auf 2 fuer "Level 2". *
- * *
- \**************************************************************************/
-
- VOID i2tolx(nocgnc)
- unsigned nocgnc;
- {
- register MBHEAD *rcvdip; /* Zeiger auf Framekopf weiterzureichendes I */
-
- while (lnkpoi->rcvd != 0) /* solange I's aus Link vorhanden */
- {
- (rcvdip = lnkpoi->rcvdil.head)->l2link = lnkpoi; /* Linkzeiger */
- rcvdip->type = 2; /* Level 2 ! */
- if (!fmlink(nocgnc,rcvdip)) /* I an hoeheren Level geben */
- return; /* Abbruch, wenn nicht angenommen */
- lnkpoi->noatou = ininat; /* angenommen, wieder Aktivitaet */
- --lnkpoi->rcvd; /* Empfangspaketezaehler updaten */
- }
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "serve received N(R)" *
- * *
- * Aktuell empfangenes N(R) (rxfctl) des aktuellen Links (lnkpoi) auswerten *
- * und entsprechend verfahren (s.u.). *
- * *
- * Return: YES - aktuell empfangenes N(R) ist okay oder Linkzustand *
- * laesst N(R)-Empfang nicht zu *
- * NO - aktuell empfangenes N(R) ist falsch *
- * *
- \**************************************************************************/
-
- BOOLEAN srxdNR()
- {
- register unsigned l2state; /* Linkstatus des aktuellen Links */
- register unsigned rxdNR; /* empfangenes N(R) */
- register unsigned newok; /* Anzahl neu bestaetigte I's */
- unsigned outstd; /* Anzahl ausstehende (nicht bestaetigte) I's */
-
- if ((l2state = lnkpoi->state) >= L2SIXFER) /* darf N(R) kommen ? */
- {
- if ( ( outstd = (lnkpoi->VS - lnkpoi->lrxdNR) & 0x07
- ) != 0
- && ( newok = ( (rxdNR = (rxfctl >> 5) & 0x07) - lnkpoi->lrxdNR
- ) & 0x07
- ) != 0 /* N(R) nur auswerten, wenn I's aus- */
- ) /* stehen und neue bestaetigt werden */
- if (newok <= outstd) /* N(R) okay ? */
- {
- lnkpoi->lrxdNR = rxdNR; /* ja, N(R) annehmen */
- clrT1(); /* T1 stoppen */
- if (newok != outstd) /* wenn immer noch I's ausstehend */
- setT1(); /* T1 neu starten */
- while (newok-- != 0)
- { /* alle neu */
- dealmb(unlink(lnkpoi->sendil.head)); /* bestaetigten */
- --lnkpoi->tosend; /* I's wegwerfen */
- }
- }
- else
- { /* nein, */
- sdfrmr(0x08); /* Kontrollfeld hat falsches N(R) */
- return (FALSE); /* N(R) nicht okay ! */
- }
-
- if ( l2state == L2SWA /* falls Linkzustand "Warten auf */
- || l2state == L2SWADBS /* Bestaetigung" ist, */
- || l2state == L2SWARBS
- || l2state == L2SWABBS
- )
- if (!rxfCR && rxfPF != 0) /* wenn empfangenes Frame */
- { /* Response mit Final war, */
- clrT1(); /* Timer 1 stoppen und */
- lnkpoi->VS = lnkpoi->lrxdNR; /* V(S) updaten */
- }
- else /* sonst Timer 1 neu */
- if (!lnkpoi->T1) setT1(); /* starten falls inaktiv */
- }
-
- return (TRUE); /* N(R) okay oder nicht benutzt */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "is next I" *
- * *
- * Testen, ob das aktuell empfangene I-Frame (rxf...) das naechste fuer den *
- * aktuellen Linkblock (lnkpoi) erwartete I-Frame ist, wenn der Linkzustand *
- * Informationstransfer zulaesst. Bei nicht erwarteter Sequenznummer *
- * entsprechende Statetable abarbeiten. *
- * *
- * Return : YES - I-Frame ist das naechste erwartete oder Linkzustand *
- * laesst keinen Informationstransfer zu *
- * NO - sonst *
- * *
- \**************************************************************************/
-
- BOOLEAN isnxti()
- {
- register unsigned iseqno; /* I Sequence Number */
-
- if (lnkpoi->state >= L2SIXFER) /* I-Transfer ? */
- if ((iseqno = (rxfctl >> 1) & 0x07) == lnkpoi->VR) /* I erwartet ? */
- if (((lnkpoi->ltxdNR + 7) & 0x07) != iseqno) /* kein Ueber- */
- { /* lauf ? */
- if (!(lnkpoi->flag & L2FBUSY)) /* wenn nicht busy, neue */
- lnkpoi->VR = (iseqno + 1) & 0x07; /* V(R) setzen */
- }
- else
- {
- sdfrmr(0x01); /* Kontrollfeld falsch/nicht implementiert */
- return (FALSE);
- }
- else /* unerwartetes I (nicht */
- { /* naechstes in Reihe) */
- l2stma(!rxfPF ? stbl26 : stb26b); /* INVALID N(S) RECEIVED */
- return (FALSE); /* unerwartetes I ! */
- }
-
- return (TRUE); /* I richtig oder Linkzustand ohne I-Transfer */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "initialize link" *
- * *
- * Aktuellen Linkblock (lnkpoi) initialisieren. Sequenzvariablen und Timer *
- * initialisieren, Quellcall/Zielcall/via-Liste/ Port setzen aus der *
- * txf...-Liste. *
- * *
- \**************************************************************************/
- VOID inilnk()
- {
- reslnk(); /* Sequenzvars/Timer init. */
- cpyid(lnkpoi->srcid,txfhdr + L2IDLEN); /* Quellcall */
- cpyid(lnkpoi->dstid,txfhdr); /* Zielcall */
- cpyidl(lnkpoi->viaidl,txfhdr + L2ILEN); /* via-Liste */
- lnkpoi->liport = txfprt; /* Port */
- setiT1(); /* initial Timer 1 */
- }
-
-
-
-
- /**************************************************************************\
- * *
- * "set initial T1" *
- * *
- * Den initialen Timer-1-Zaehlerstand des aktuellen Linkblocks (lnkpoi) *
- * (= derjenige Zaehlerstand, der bei Start des Timer 1 immer gesetzt wird) *
- * berechnen nach der Formel : *
- * *
- * *
- * initT1 [1/100 sec] *
- * *
- * = (Anzahl der Digipeater * 2 + 1) * FRACK [sec] * 100 *
- * | *
- * +---> fuer jeden Linkblock *
- * und im Linkblock setzen (initT1). einzeln, snglT1 *
- * *
- \**************************************************************************/
-
- VOID setiT1()
- {
- register char *viap; /* Zeiger in via-Liste */
- register unsigned n; /* Digizaehler */
-
- viap = lnkpoi->viaidl; /* Anfang via-Liste */
- n = 0; /* noch kein Digi gezaehlt */
- while (*viap != '\0') /* Digianzahl ermitteln */
- {
- ++n;
- viap += L2IDLEN;
- }
- n *= 2; /* Digianzahl * 2 + 1 */
- ++n;
- lnkpoi->initT1 = lnkpoi->snglT1 * n * 100; /* " * FRACK * 100 */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "messaged clear link" *
- * *
- * Aktuellen Link aufloesen (siehe clrlnk()) und entsprechende Meldung an *
- * hoehere Level geben ("Disconnected from"). *
- * *
- \**************************************************************************/
-
- VOID mclrlk()
- {
- clrlnk(); /* Link aufloesen */
- l2tolx(L2MDISCF); /* und hoehere Level informieren */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "clear link" *
- * *
- * Aktuellen Link (lnkpoi) aufloesen. Alle Sequenzvariablen und Timer *
- * zuruecksetzen, Sende- und Empfangsinfoframelise loeschen, Linkblock neu *
- * mit AX.25-Parametern besetzen, Anzahl der aktiven Links (nmblks) um 1 *
- * erniedrigen. *
- * *
- \**************************************************************************/
-
- VOID clrlnk()
- {
- reslnk(); /* Sequenzvars/Timer ruecksetzen */
- dealml(&lnkpoi->rcvdil); /* Empfangsinfoliste loeschen */
- dealml(&lnkpoi->sendil); /* Sendeinfoliste loeschen */
- lnkpoi->rcvd = lnkpoi->tosend = 0; /* entsprechende Zaehler loeschen */
- --nmblks; /* nun ein aktiver Link weniger */
- inilbl(); /* Linkblock "frisch" */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "disconnect" *
- * *
- * Disconnect des aktuellen Links (lnkpoi) einleiten. Alle Sequenzvariablen *
- * und Timer zuruecksetzen, DISC senden, neuer Status "Disconnect request". *
- * *
- \**************************************************************************/
-
- VOID disc()
- {
- reslnk(); /* Sequenzvars/Timer ruecksetzen */
- xdisc(); /* DISC senden */
- lnkpoi->state = L2SDSCRQ; /* Linkstatus "Disc Request" */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "reset link" *
- * *
- * Aktuellen Link (lnkpoi) zuruecksetzen. Alle Sequenzvariablen und Timer *
- * initialisieren. *
- * *
- \**************************************************************************/
-
- VOID reslnk()
- {
- lnkpoi->VS
- = lnkpoi->VR
- = lnkpoi->ltxdNR
- = lnkpoi->lrxdNR
- = lnkpoi->flag
- = 0;
- clrT1();
- clrT2();
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "initialize link block" *
- * *
- * Aktuellen Linkblock (lnkpoi) mit AX.25-Parametern initialisieren. *
- * Loeschen des Quellrufzeichens, Setzen von FRACK, MAXFRAME, RETRY, *
- * AX25V2. *
- * *
- \**************************************************************************/
-
- VOID inilbl()
- {
- *lnkpoi->srcid = '\0';
- lnkpoi->snglT1 = Fpar;
- lnkpoi->k = Opar;
- lnkpoi->N2 = Npar;
- lnkpoi->V2link = Vpar;
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "send outstanding I's" *
- * *
- * Aus dem aktuellen Linkblock (lnkpoi) soviele I-Frames senden, wie im *
- * Moment unbestaetigt ausstehen. *
- * *
- \**************************************************************************/
-
- VOID sdoi()
- {
- register unsigned nmbtos; /* Anzahl I's zu senden */
-
- if (nmbtos = (lnkpoi->VS - lnkpoi->lrxdNR) & 0x07) /* wieviel darf */
- { /* ich ? */
- lnkpoi->VS = lnkpoi->lrxdNR; /* V(S) resetten */
- sdi(nmbtos); /* I's senden */
- }
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "send I" *
- * *
- * Aus dem aktuellen Linkblock (lnkpoi) maximal max I-Frames aus der *
- * Infomessageliste aufbauen und senden. Infos ueber 256 Bytes werden *
- * gesplittet und dann gesendet. Die Frames werden als Commandframes ohne *
- * Poll/Final-Bit gesendet. V(S) wird fuer jedes gesendete Frame erhoeht *
- * modulo 7. Timer 2 und Timer 3 werden abgeschaltet. *
- * *
- \**************************************************************************/
-
- VOID sdi(max)
- unsigned max;
- {
- register unsigned n; /* Zaehler zu sendende Infos */
- register MBHEAD *sendip; /* Kopfzeiger Infobuffer */
- register MBHEAD *fbp; /* Kopfzeiger Framebuffer */
-
- for ( n = 0, sendip = lnkpoi->sendil.head; /* maximal max I-Frames */
- n < lnkpoi->tosend && n < max; /* aus der Linkblock- */
- ++n, sendip = sendip->nextmh /* infoliste senden */
- ) /* wenn vorhanden */
- {
- stxfad(); /* Frameadresse aufbauen */
- txfV2 = lnkpoi->V2link; /* Version */
- txfCR = L2CCR; /* Command ! */
- txfPF = 0; /* kein Poll/Final */
- txfctl = setNR(lnkpoi->VS << 1); /* Controlbyte I setzen */
- ++lnkpoi->VS; /* V(S) erhoehen */
- lnkpoi->VS &= 0x07; /* modulo 7 */
- putchr(sendip->l2fflg, /* Frame aufbauen, PID */
- fbp = makfhd(L2FT1ST));
- #ifdef MODIFIED
-
- /* in modified version, to permit big frames, only permit splitting
- * if the packet is NOT a higher layer protocol !
- */
- if( splcpy( 256, fbp, sendip, sendip->l2fflg == L2CPID )
- /*==YES*/ ) /* Message hineinkopieren */
- #else
- if(splcpy(256,fbp,sendip) /*==YES*/) /* Message hineinkopieren */
- #endif
- ++lnkpoi->tosend; /* falls Split eine mehr */
- sdl2fr(fbp); /* Frame senden */
- clrT2(); /* Timer 2 abschalten */
- clrT3(); /* Timer 3 abschalten */
- }
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "split copy" *
- * *
- * Die Bytes aus dem Messagebuffer, auf dessen Kopf mbhd zeigt, in den *
- * Framebuffer, auf dessen Kopf fbp zeigt, kopieren. Es werden hoechstens *
- * max Bytes kopiert, hat die Message mehr Bytes, so wird ein neuer *
- * Messagebuffer angelegt, die restlichen Messagebytes werden in diesen *
- * Buffer kopiert, der neue Buffer wird hinter den alten Messagebuffer *
- * gehaengt, der Putcount des alten Buffers wird auf max gestellt, das *
- * "more follows"-Flag morflg des neuen Buffers wird geloescht, l2fflg wird *
- * uebertragen. *
- * *
- * Return : YES - der Messagebuffer wurde aufgesplittet *
- * NO - sonst *
- * *
- * This modified version adds a boolean parameter to say whether it is *
- * OK to split the frame or not. *
- \**************************************************************************/
-
- #ifdef MODIFIED
- BOOLEAN splcpy(max,fbp,mbhd, can_be_split)
- unsigned max;
- MBHEAD *fbp;
- register MBHEAD *mbhd;
- BOOLEAN can_be_split;
- #else
- BOOLEAN splcpy(max,fbp,mbhd )
- unsigned max;
- MBHEAD *fbp;
- register MBHEAD *mbhd;
- #endif
- {
- char *mbbpsa; /* Sicherung mbbp */
- BOOLEAN split; /* TRUE: Split erfolgt */
- unsigned mbgcsa; /* Sicherung mbgc */
- unsigned mbgc2; /* mbgc alt -> mbpc alt */
- register unsigned n; /* Zaehler */
- register MBHEAD *mbhd2; /* Kopfzeiger neuer Messagebuffer */
-
- split = NO; /* zunaechst nichts gesplittet */
- mbbpsa = mbhd->mbbp; /* Bufferpointer sichern */
- mbgcsa = mbhd->mbgc; /* Getcounter sichern */
- #ifdef MODIFIED
- n = mbhd->mbpc - mbhd->mbgc;
- if( n > max && can_be_split )
- n = max;
- while( n-- )
- #else
- for (n = 0; mbhd->mbgc < mbhd->mbpc && n < max; ++n)
- #endif
- putchr(getchr(mbhd),fbp); /* maximal max Bytes kopieren */
- if (mbhd->mbgc < mbhd->mbpc) /* noch Bytes ueber -> Split ! */
- {
- mbgc2 = mbhd->mbgc; /* Getcount fuer spaeter merken */
- mbhd2 = allocb(); /* neuen Buffer erzeugen */
- #ifdef MODIFIED
- mhtyp_copy( mbhd, mbhd2 );
- #else
- while (mbhd->mbgc < mbhd->mbpc) /* die restlichen Bytes in diesen */
- putchr(getchr(mbhd),mbhd2); /* Buffer kopieren */
- #endif
- rwndmb(mbhd2); /* neuen Buffer rewinden */
- mbhd2->morflg = NO; /* noch dem neuen folgt keiner */
- mbhd2->l2fflg = mbhd->l2fflg; /* Frameflag uebertragen */
- relink(mbhd2,mbhd); /* neu. Buf. hinter alten haengen */
- mbhd->mbpc = mbgc2; /* alter Buffer nur max Zeichen ! */
- split = YES; /* wir mussten splitten */
- }
- mbhd->mbbp = mbbpsa; /* Bufferpointer restaurieren */
- mbhd->mbgc = mbgcsa; /* Getcount restaurieren */
- return (split); /* Split oder nicht */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "send UI" *
- * *
- * UI-Frame aufbauen und senden. Das UI-Frame wird an ID dest geschickt *
- * ueber den Port port und die via-Liste (nullterminiert) vial, als Quelle *
- * wird source genommen, die Infobytes des Frames stehen im Messagebuffer, *
- * auf dessen Kopf mbhd zeigt, die PID wird aus l2fflg dieses Buffers *
- * genommen. *
- * *
- \**************************************************************************/
-
- VOID sdui(vial,dest,source,port,mbhd)
- char *vial;
- char *dest;
- char *source;
- unsigned port;
- register MBHEAD *mbhd;
- {
- register MBHEAD *fbp; /* Zeiger auf Framekopf */
-
- cpyid(txfhdr + L2IDLEN,source); /* Quelle setzen */
- cpyid(txfhdr,dest); /* Ziel setzen */
- cpyidl(txfhdr + L2ILEN,vial); /* via-Liste setzen */
- txfprt = port; /* Port setzen */
- txfV2 = Vpar; /* Protokollversion */
- txfCR = L2CCR; /* Command ! */
- txfPF = 0; /* kein Poll/Final */
- txfctl = L2CUI; /* UI-Frame ! */
- putchr(mbhd->l2fflg,fbp = makfhd(0)); /* Frame aufbauen, PID */
- #ifdef MODIFIED
- mhtyp_copy( mbhd, fbp );
- #else
- while (mbhd->mbgc < mbhd->mbpc) /* Message -> Frame */
- putchr(getchr(mbhd),fbp);
- #endif
- sdl2fr(fbp); /* Frame senden */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "level 2 state machine" *
- * *
- * Ausfuehren der Zustandsuebergangsfunktion des Linkstatus (state) des *
- * aktuellen Linkblocks (lnkpoi) in der Statetable stbl, danach einnehmen *
- * des durch die Statetable gegebenen neuen Zustands. *
- * *
- * In der Protokollversion 1 (dort gibt es nur 5 Zustaende), alle Zustaende *
- * oberhalb Informationstransfer auf Informationstransfer setzen. *
- * *
- \**************************************************************************/
-
- VOID l2stma(stbl)
- register STENTRY stbl[];
- {
- (*stbl[lnkpoi->state].func)(); /* Funktion ... */
- lnkpoi->state = stbl[lnkpoi->state].newstate; /* neuer Zustand */
- if (!lnkpoi->V2link && lnkpoi->state > L2SIXFER) /* Version 1 */
- lnkpoi->state = L2SIXFER; /* Stutzung */
- }
-
-
-
- /* Ende von L2B.C */